import { ArrayMethods } from './arr'
import Dep from './dep'

export default function observer(data) {
  // 不是对象不进行劫持
  if (typeof data !== 'object' || data === null) {
    return data;
  }
  // 返回劫持对象
  return new Observer(data);
}


class Observer {
  constructor(value) {
    Object.defineProperty(value, '__ob__', {
      enumerable: false,
      value: this
    })
    // 对象类型添加dep
    this.dep = new Dep();

    if (Array.isArray(value)) {
      value.__proto__ = ArrayMethods;
      // 数组对象劫持
      this.observeArray(value);
    } else {
      this.walk(value)
    }
  }

  walk(data) {
    let keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];
      let value = data[key];
      defineReactive(data, key, value);
    }
  }

  observeArray(value) {
    for (let i = 0; i < value.length; i++) {
      observer(value[i])
    }
  }
}

/**
 * 对对象中的属性进行劫持
 * @param data 对象
 * @param key 属性
 * @param value 值
 */
function defineReactive(data, key, value) {
  // 递归代理
  let childDep = observer(value);

  let dep = new Dep();

  Object.defineProperty(data, key, {
    get() {
      if (Dep.target) {
        if (childDep.dep) {
          childDep.dep.depend();
        } else {
          dep.depend();
        }
      }
      return value;
    }, set(newValue) {
      if (newValue === value) return;
      // 设置值为对象时，在进行代理
      observer(newValue);
      value = newValue;
      dep.notify();
    }
  })
}